package org.study.mybatis.generator.plugins;

import org.mybatis.generator.api.*;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.internal.util.StringUtility;
import org.mybatis.generator.plugins.MapperAnnotationPlugin;
import org.study.mybatis.generator.util.PluginUtils;

import java.util.List;

/**
 * mybatis-generator集成lombok
 * 参考 {@link MapperAnnotationPlugin}
 * 参考 https://www.cnblogs.com/java-lzy/p/15137673.html
 * 参考 https://blog.csdn.net/weixin_55586010/article/details/129292274
 *
 * @author doveylovey
 * @version v1.0.0
 * @email 1135782208@qq.com
 * @date 2023年12月09日
 */
public class LombokPlugin extends PluginAdapter {
    /**
     * 是否生成 @Data 注解
     */
    private boolean data;
    /**
     * 是否生成 @Builder 注解
     */
    private boolean builder;
    /**
     * 是否生成 @ToString 注解
     */
    private boolean toString;
    /**
     * 是否生成 @NoArgsConstructor 注解
     */
    private boolean noArgsConstructor;
    /**
     * 是否生成 @AllArgsConstructor 注解
     */
    private boolean allArgsConstructor;
    /**
     * 是否生成 @Accessors 注解，@Accessors(chain = true)的作用：使成员属性的set()方法不再返回void，而是返回对象本身，从而实现链式赋值
     */
    private boolean accessors;
    /**
     * 是否生成 @EqualsAndHashCode 注解，作用：覆盖Java类中的equals和hashCode方法，当设置callSuper=false时，表示不调用父类的equals()和hashCode()方法，这意味着只有当前类中的字段被用于比较和哈希计算。
     * 当属性 callSuper=false 时进行对象属性比较：只比较子类的属性，即：如果两个对象子类属性一致，父类属性不一致，返回的也是true。
     * 当属性 callSuper=true 时进行对象属性比较：子类和父类一同进行比较，即：如果两个对象子类属性一致，父类属性不一致，返回的是false；只有子类和继承类的属性全都一致时，才会返回true。
     */
    private boolean equalsAndHashCode;

    @Override
    public boolean validate(List<String> warnings) {
        this.data = Boolean.parseBoolean(this.properties.getProperty("data"));
        this.builder = Boolean.parseBoolean(this.properties.getProperty("builder"));
        this.toString = Boolean.parseBoolean(this.properties.getProperty("toString"));
        this.noArgsConstructor = Boolean.parseBoolean(this.properties.getProperty("noArgsConstructor"));
        this.allArgsConstructor = Boolean.parseBoolean(this.properties.getProperty("allArgsConstructor"));
        this.accessors = Boolean.parseBoolean(this.properties.getProperty("accessors"));
        this.equalsAndHashCode = Boolean.parseBoolean(this.properties.getProperty("equalsAndHashCode"));
        return true;
    }

    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        // 为实体类导入lombok包、添加lombok注解、添加代码注释
        if (this.data) {
            topLevelClass.addImportedType("lombok.Data");
            topLevelClass.addAnnotation("@Data");
        }
        if (this.builder) {
            topLevelClass.addImportedType("lombok.Builder");
            topLevelClass.addAnnotation("@Builder");
        }
        if (this.toString) {
            topLevelClass.addImportedType("lombok.ToString");
            topLevelClass.addAnnotation("@ToString");
        }
        if (this.noArgsConstructor) {
            topLevelClass.addImportedType("lombok.NoArgsConstructor");
            topLevelClass.addAnnotation("@NoArgsConstructor");
        }
        if (this.allArgsConstructor) {
            topLevelClass.addImportedType("lombok.AllArgsConstructor");
            topLevelClass.addAnnotation("@AllArgsConstructor");
        }
        if (this.accessors) {
            topLevelClass.addImportedType("lombok.experimental.Accessors");
            topLevelClass.addAnnotation("@Accessors(chain = true)");
        }
        if (this.equalsAndHashCode) {
            topLevelClass.addImportedType("lombok.EqualsAndHashCode");
            topLevelClass.addAnnotation("@EqualsAndHashCode(callSuper = false)");
        }
        // 为实体类添加注释
        topLevelClass.addJavaDocLine("/**");
        String remarks = introspectedTable.getRemarks();
        if (StringUtility.stringHasValue(remarks)) {
            String[] remarkLines = remarks.split(System.getProperty("line.separator"));
            for (String remarkLine : remarkLines) {
                topLevelClass.addJavaDocLine(" * " + remarkLine);
            }
        }
        StringBuilder sb = new StringBuilder();
        sb.append(" * ").append("实体类，对应数据库表：" + introspectedTable.getFullyQualifiedTable());
        topLevelClass.addJavaDocLine(sb.toString());
        topLevelClass.addJavaDocLine(" *");
        sb.setLength(0);
        sb.append(" * @author " + PluginUtils.getAuthor());
        topLevelClass.addJavaDocLine(sb.toString());
        sb.setLength(0);
        // sb.append(" * @date " + PluginUtils.getNowStr());
        sb.append(" * @mbg.generated " + PluginUtils.getNowStr());
        topLevelClass.addJavaDocLine(sb.toString());
        topLevelClass.addJavaDocLine(" */");
        return true;
    }

    @Override
    public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
        // 为实体类中的字段添加注释
        field.addJavaDocLine("/**");
        field.addJavaDocLine(" * 数据库字段名称：" + introspectedColumn.getActualColumnName());
        String remarks = introspectedColumn.getRemarks();
        if (StringUtility.stringHasValue(remarks)) {
            String[] remarkLines = remarks.split(System.getProperty("line.separator"));
            for (String remarkLine : remarkLines) {
                field.addJavaDocLine(" * " + remarkLine);
            }
        }
        field.addJavaDocLine(" */");
        return true;
    }

    @Override
    public boolean clientGenerated(Interface interfaze, IntrospectedTable introspectedTable) {
        // 为XxxMapper.java添加注释
        interfaze.addJavaDocLine("/**");
        interfaze.addJavaDocLine(" * Mapper接口，操作数据库表：" + introspectedTable.getFullyQualifiedTable());
        interfaze.addJavaDocLine(" * ");
        interfaze.addJavaDocLine(" * @author " + PluginUtils.getAuthor());
        interfaze.addJavaDocLine(" * @mbg.generated " + PluginUtils.getNowStr());
        interfaze.addJavaDocLine(" */");
        return true;
    }

    @Override
    public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) { // 不生成getter
        // 是否生成Setter方法
        return !this.data;
    }

    @Override
    public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) { // 不生成setter
        // 是否生成Getter方法
        return !this.data;
    }
}
